﻿#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <string.h>

#define MAX_SIZE 500
#define WIDTH 640
#define HEIGHT 480
#define GRID_SIZE 20  // 网格尺寸调整为20像素

enum DIR { UP, DOWN, LEFT, RIGHT };

struct pos {
    int x;
    int y;
};

struct Snake {
    pos cur[MAX_SIZE];
    int size;
    int len;
    DIR dir;
    int score1;//每次吃果子得分
    int score;
    int sleeptime;
};

struct Snake snake;
struct pos food;
int highest_score = 0;
int game_running = 1;

// 函数声明
void printsnake();
void welcometogame();
void createMap();
void File_out();
void File_in();
void initsnake();
void createfood();
int biteself();
int cantcrosswall();
void speedup();
void speeddown();
void keyboardControl();
void explation();
void draw();
void move();
void eatfood();
int showGameOverScreen();

// 从文件读取最高分
void File_in() {
    FILE* fp;
    errno_t err = fopen_s(&fp, "save.txt", "r");
    if (err == 0 && fp != NULL) {
        fscanf_s(fp, "%d", &highest_score);
        fclose(fp);
    }
}

// 写入最高分到文件
void File_out() {
    FILE* fp;
    errno_t err = fopen_s(&fp, "save.txt", "w");
    if (err == 0 && fp != NULL) {
        fprintf(fp, "%d", highest_score);
        fclose(fp);
    }
}
void printsnake() {
    settextcolor(YELLOW);
    settextstyle(64, 0, "华文行楷");
    outtextxy(150, 50, "贪吃蛇");
    settextcolor(GREEN);
    settextstyle(20, 0, "微软雅黑");
    outtextxy(500, 450, "作者：Feeling");
}

// 欢迎界面
void welcometogame() {
    cleardevice();
    printsnake();

    settextcolor(LIGHTGREEN);
    settextstyle(24, 0, "宋体");
    outtextxy(260, 200, "1. 开始游戏");
    outtextxy(260, 250, "2. 游戏说明");
    outtextxy(260, 300, "3. 最高分");
    outtextxy(260, 350, "4. 退出游戏");

    FlushBatchDraw();
}

// 创建游戏地图(空心方块)
void createMap() {
    setlinecolor(LIGHTCYAN);

    // 绘制垂直边框
    for (int x = 0; x <= WIDTH; x += GRID_SIZE) {
        for (int y = 40; y <= HEIGHT; y += GRID_SIZE) {
            rectangle(x, y, x + GRID_SIZE, y + GRID_SIZE);
        }
    }
}

// 初始化蛇
void initsnake() {
    snake.len = 3;
    snake.dir = RIGHT;
    snake.sleeptime = 300;
    snake.score1 = 10;
    snake.score = 0;

    // 初始位置居中
    int start_x = (WIDTH / GRID_SIZE / 2) * GRID_SIZE;
    int start_y = (HEIGHT / GRID_SIZE / 2) * GRID_SIZE;

    for (int i = 0; i < snake.len; i++) {
        snake.cur[i].x = start_x - i * GRID_SIZE;
        snake.cur[i].y = start_y;
    }
}

// 生成食物
void createfood() {
    bool overlap;
    do {
        overlap = false;
        food.x = (rand() % (WIDTH / GRID_SIZE)) * GRID_SIZE;
        food.y = 40 + (rand() % ((HEIGHT - 40) / GRID_SIZE)) * GRID_SIZE;

        // 检查是否与蛇身重叠
        for (int i = 0; i < snake.len; i++) {
            if (food.x == snake.cur[i].x && food.y == snake.cur[i].y) {
                overlap = true;
                break;
            }
        }
        
    } while (overlap);
}

// 判断是否咬到自己
int biteself() {
    for (int i = 1; i < snake.len; i++) {
        if (snake.cur[0].x == snake.cur[i].x &&
            snake.cur[0].y == snake.cur[i].y)
            return 1;
    }
    return 0;
}

// 判断撞墙
int cantcrosswall() {
    return (snake.cur[0].x < 0 || snake.cur[0].x >= WIDTH ||
        snake.cur[0].y < 40 || snake.cur[0].y >= HEIGHT);
}

// 加速
void speedup() {
    if (snake.sleeptime > 50) snake.sleeptime -= 30;
    snake.score1 += 2;

	if (snake.sleeptime>=320) snake.score1 = 2; 

}

// 减速
void speeddown() {
    snake.sleeptime += 30;
    if (snake.score1 > 0) snake.score1 -= 2;
    if (snake.score1 <= 1) snake.score1 = 1;

}

// 键盘控制
void keyboardControl() {
    if (GetAsyncKeyState(VK_UP) & 0x8000) {
        if (snake.dir != DOWN) snake.dir = UP;
    }
    else if (GetAsyncKeyState(VK_DOWN) & 0x8000) {
        if (snake.dir != UP) snake.dir = DOWN;
    }
    else if (GetAsyncKeyState(VK_LEFT) & 0x8000) {
        if (snake.dir != RIGHT) snake.dir = LEFT;
    }
    else if (GetAsyncKeyState(VK_RIGHT) & 0x8000) {
        if (snake.dir != LEFT) snake.dir = RIGHT;
    }

    // 功能键处理
    if (GetAsyncKeyState(VK_ADD) & 0x8000) speedup();
    if (GetAsyncKeyState(VK_SUBTRACT) & 0x8000) speeddown();
}

// 游戏说明界面
void explation() {
    cleardevice();
    settextcolor(LIGHTMAGENTA);
    settextstyle(24, 0, "宋体");

    outtextxy(50, 50, "【游戏规则】");
    outtextxy(50, 100, "1. 使用方向键控制蛇的移动");
    outtextxy(50, 150, "2. +加速/-减速(小键盘)");
    outtextxy(50, 200, "3. 吃到食物增长身体并得分");
    outtextxy(50, 250, "4. 撞墙或咬到自己游戏结束");
    outtextxy(50, 300, "按任意键返回主菜单...");

    FlushBatchDraw();
    _getch();
}

// 绘制游戏元素
void draw() {
    cleardevice();
    createMap();

    setfillcolor(YELLOW);
    for (int i = 0; i < snake.len; i++) {
        solidrectangle(snake.cur[i].x, snake.cur[i].y,
            snake.cur[i].x + GRID_SIZE,
            snake.cur[i].y + GRID_SIZE);
    }

    // 绘制食物（随机颜色）
    setfillcolor(HSVtoRGB(rand() % 360, 0.8, 1));
    solidrectangle(food.x, food.y, food.x + GRID_SIZE, food.y + GRID_SIZE);

    // 绘制分数信息
    char str[50];
    settextcolor(WHITE);
    sprintf_s(str, "得分：%d  最高分：%d", snake.score, highest_score);
    outtextxy(20, 10, str);
    outtextxy(WIDTH-350, 10, "+加速/-减速(小键盘) ESC退出");

    FlushBatchDraw();
}

// 移动逻辑
void move() {
    // 移动身体
    for (int i = snake.len - 1; i > 0; i--) {
        snake.cur[i] = snake.cur[i - 1];
    }

    // 移动头部
    switch (snake.dir) {
    case UP:    snake.cur[0].y -= GRID_SIZE; break;
    case DOWN:  snake.cur[0].y += GRID_SIZE; break;
    case LEFT:  snake.cur[0].x -= GRID_SIZE; break;
    case RIGHT: snake.cur[0].x += GRID_SIZE; break;
    }
}

// 吃食物检测
void eatfood() {
    if (snake.cur[0].x == food.x && snake.cur[0].y == food.y) {
        snake.len++;
        snake.score += snake.score1;
        createfood();
        speedup(); // 吃到食物自动加速
    }
}

// 游戏结束界面
int showGameOverScreen() {
    cleardevice();

    settextcolor(RED);
    settextstyle(48, 0, "华文琥珀");
    outtextxy(200, 100, "游 戏 结 束");

    char str[100];
    settextstyle(24, 0, "宋体");
    sprintf_s(str, "本次得分：%d", snake.score);
    outtextxy(250, 200, str);

    if (snake.score > highest_score) {
        outtextxy(150, 250, "新纪录! 恭喜打破最高分!");
    }
    else {
        sprintf_s(str, "距离最高分还差 %d 分", highest_score - snake.score);
        outtextxy(150, 250, str);
    }

    outtextxy(200, 350, "1. 重新开始");
    outtextxy(200, 400, "2. 退出游戏");

    FlushBatchDraw();

    while (1) {
        if (_kbhit()) {
            int key = _getch();
            if (key == '1') return 1;
            if (key == '2') return 0;
        }
    }
}

int main() {
    initgraph(WIDTH, HEIGHT, SHOWCONSOLE);
    srand((unsigned)time(NULL));
    File_in();

    while (1) {
        welcometogame();
        char choice = _getch();

        switch (choice) {
        case '1': // 开始游戏
            initsnake();
            createfood();
            game_running = 1;

            BeginBatchDraw();
            while (game_running) {
                keyboardControl();



                move();
                eatfood();
                if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
                    game_running = 0;
                // 碰撞检测
                if (cantcrosswall() || biteself())
                    game_running = 0;

                draw();
                Sleep(snake.sleeptime);
            }
            EndBatchDraw();

            // 更新最高分
            if (snake.score > highest_score) {
                highest_score = snake.score;
                File_out();
            }

            if (showGameOverScreen() == 0)
                return 0;
            break;

        case '2': // 游戏说明
            explation();
            break;

        case '3': // 显示最高分
            cleardevice();
            char str[50];
            sprintf_s(str, "当前最高分：%d", highest_score);
            outtextxy(250, 200, str);
            outtextxy(200, 300, "按任意键返回...");
            FlushBatchDraw();
            _getch();
            break;

        case '4': // 退出游戏
            closegraph();
            return 0;
        }
    }
}